#!/usr/bin/env python
#
# SdrScript - User Interface for Control functions
# 
# User: bob
# Date: 24/04/14
# Copyright (C) 2014 by G3UKB Bob Cowdery
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#    
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#    
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#    
#  The author can be reached by email at:   
#     bob@bobcowdery.plus.com
#

"""
    This is a 3 layer architecture:
    1. The top layer Python code that does high level control (discover/start/stop), manages
    the input and output command and control bytes and initiates the processing. The main user
    interface is implemented at this level. This layer supports an API to the sever process.
    
    2. The middle layer Cython code that provides the server API implementation, orchestrates
    the processing and glues together the interpreted Python layer and the pipeline 'C' code. Whilst
    this layer is translated to C and compiled it is not necessarily faster than the Python bytecode
    would be although certain speedups can be implemented. However, the preferred method is to keep
    this layer pythonic and implement all time critical functions in C.
    
    3. The high performance C code layer providing the 'decode - DSP - encode' pipeline and local audio
    input and output.
    
"""

# System imports
import os,sys
import traceback
from time import sleep
import logging

from PyQt4 import QtCore, QtGui

# Application imports
sys.path.append('..')
from common.defs import *
import common.instance_cache as instance_cache
from common import broker
from api.api import AudioApi
from api.api import ControlApi
from api.api import MetisApi

import ui.control.control_ui as control
import ui.receiver.rx_ui as receiver
import metis.metis as metis
import transcript.transcript as transcript

# Test mode is for doing UI changes without actually running the radio.
TEST_MODE = False

"""
Class implementing the main control flow of SdrScript
"""
class SdrScript:
    
    def main(self):
        
        # Initiate processing and wait for the user to exit the application
        # - or for a failure to occur.
        ctrl = None
        rx = None        
        
        try:
            # Create our transcript processor
            self.__transcript_q = transcript.transcript_init()
            self.__transcript_q.put ((BOTH, logging.INFO, 'py.sdr_script', 'Initialising...'))
            # The one and only QApplication 
            qt_app = QtGui.QApplication(sys.argv)

            # Register event types with the broker
            broker.declare_event(TX_FREQ_EVNT)
            broker.declare_event(RX_0_FREQ_EVNT)
            broker.declare_event(ANTENNA_EVNT)
            broker.declare_event(RATE_EVNT)
            broker.declare_event(NUM_RX_EVNT)
            broker.declare_event(BLK_SZ_EVNT)
            broker.declare_event(DUPLEX_EVNT)
            broker.declare_event(TX_ENABLE_EVNT)
            broker.declare_event(AUDIO_CH_EVNT)
            broker.declare_event(ANTENNA_EVNT)
            broker.declare_event(DISPLAY_EVNT)
            broker.declare_event(RESET_EVNT)
            
            # Create the metis controller object
            metis_imp = metis.Metis(self.__transcript_q)
            # Create and run the control window user interface
            # Note, if set in the configuration this will also apply power via the IP9258 IP Power Controller
            # This is why the control UI is run before discovery
            ctrl = control.Control(metis_imp, self.__transcript_q, TEST_MODE)
            ctrl.run()
            instance_cache.addToCache('Controller', ctrl)
            if not TEST_MODE:
                # Try and find a Metis
                self.__transcript_q.put ((BOTH, logging.INFO, 'py.sdr_script', 'Starting Metis discovery...'))
                self.__metis_found = True
                while not metis_imp.discover():
                    self.__metis_found = False
                    self.__transcript_q.put ((BOTH, logging.INFO, 'py.sdr_script', 'Failed to find HPSDR hardware!'))
                    reply = QtGui.QMessageBox.question( None, 'Discover',
                                                        "Failed to find HPSDR hardware. Try again?",
                                                        QtGui.QMessageBox.Yes | 
                                                        QtGui.QMessageBox.No,
                                                        QtGui.QMessageBox.No)
    
                    if reply == QtGui.QMessageBox.Yes:
                        if metis_imp.discover():
                            self.__metis_found = True
                            break
                    else:
                        break
                if self.__metis_found:
                    self.__transcript_q.put ((BOTH, logging.INFO, 'py.sdr_script', 'Discovery successful'))
                    ctrl.set_metis_running(True)
                else:
                    self.__transcript_q.put ((BOTH, logging.INFO, 'py.sdr_script', 'Discovery failed. Run is disabled but the configuration may be changed.'))
                    ctrl.set_metis_running(False)
            
            # Create the API instances and add to the instance cache to save passing references all over the place
            # Must be in this order as ControlApi creates the server instance
            metis_sock, metis_address, METIS_PORT = metis_imp.get_connect_info()
            instance_cache.addToCache('Control_API', ControlApi(metis_sock, metis_address, METIS_PORT, self.__transcript_q))
            instance_cache.addToCache('Metis_API', MetisApi(self.__transcript_q))
            instance_cache.addToCache('Audio_API', AudioApi())

        except Exception as e:
            self.__transcript_q.put ((BOTH, logging.INFO, 'py.sdr_script', 'Exception [%s][%s]' % (str(e), traceback.format_exc())))
            if ctrl != None:
                ctrl.quit()
            return 0
        
        # Enter the Qt event loop. This only returns on exit or quit
        self.__transcript_q.put ((BOTH, logging.INFO, 'py.sdr_script', 'Entering run state...'))
        r = qt_app.exec_()

        # Stop the transcript
        self.__transcript_q.put ((BOTH, logging.INFO, 'py.sdr_script', 'Sdr_script exiting...'))
        sleep(2)
        transcript.transcript_close(self.__transcript_q)
        
        return r
    
#===============================================================================
# Main code
def main():
    
    try:  
        script = SdrScript()
        sys.exit(script.main())
        
    except Exception as e:
        print ('Exception','Exception [%s][%s]' % (str(e), traceback.format_exc()))
        
if __name__ == '__main__':
    main()
